package org.hhf.command;

import org.hhf.core.*;
import org.hhf.pubsub.PubSubRedis;
import org.hhf.transaction.TransactionRedis;
import org.hhf.persistence.PersistenceManager;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * CommandProcessor类负责解析和执行Redis命令
 * 实现了nano-redis的所有核心功能
 */
public class CommandProcessor {
    private final RedisCore core;
    private final StringRedis stringRedis;
    private final ListRedis listRedis;
    private final HashRedis hashRedis;
    private final SetRedis setRedis;
    private final SortedSetRedis sortedSetRedis;
    private final PubSubRedis pubSubRedis;
    private final TransactionRedis transactionRedis;
    private final PersistenceManager persistenceManager;
    
    // 存储客户端连接的订阅者
    private final ConcurrentHashMap<String, ClientSubscriber> clientSubscribers = new ConcurrentHashMap<>();
    
    public CommandProcessor() {
        this.core = new RedisCore();
        this.stringRedis = new StringRedis(core);
        this.listRedis = new ListRedis(core);
        this.hashRedis = new HashRedis(core);
        this.setRedis = new SetRedis(core);
        this.sortedSetRedis = new SortedSetRedis(core);
        this.pubSubRedis = new PubSubRedis();
        this.transactionRedis = new TransactionRedis(core);
        this.persistenceManager = new PersistenceManager(core, "data");
        
        // 尝试从持久化文件恢复数据
        persistenceManager.load();
    }

    /**
     * 处理Redis命令
     */
    public Object processCommand(String commandLine) {
        if (commandLine == null || commandLine.trim().isEmpty()) {
            return "-ERR wrong number of arguments for command";
        }

        // 解析命令
        String[] parts = parseCommand(commandLine);
        if (parts.length == 0) {
            return "-ERR unknown command";
        }

        // 命令转换为大写
        String command = parts[0].toUpperCase();
        String[] args = Arrays.copyOfRange(parts, 1, parts.length);

        // 记录写命令到日志
        if (isWriteCommand(command)) {
            persistenceManager.logCommand(command, args);
        }

        // 根据命令类型分发处理
        switch (command) {
            // 键操作命令
            case "SET":
                return handleSet(args);
            case "GET":
                return handleGet(args);
            case "DEL":
                return handleDel(args);
            case "EXPIRE":
                return handleExpire(args);
            case "TTL":
                return handleTtl(args);
            case "EXISTS":
                return handleExists(args);
                
            // 字符串命令
            case "INCR":
                return handleIncr(args);
            case "DECR":
                return handleDecr(args);
            case "MSET":
                return handleMset(args);
            case "MGET":
                return handleMget(args);
                
            // 列表命令
            case "LPUSH":
                return handleLpush(args);
            case "RPUSH":
                return handleRpush(args);
            case "LPOP":
                return handleLpop(args);
            case "RPOP":
                return handleRpop(args);
            case "LRANGE":
                return handleLrange(args);
            case "BLPOP":
                return handleBlpop(args);
                
            // 集合命令
            case "SADD":
                return handleSadd(args);
            case "SREM":
                return handleSrem(args);
            case "SMEMBERS":
                return handleSmembers(args);
            case "SINTER":
                return handleSinter(args);
            case "SUNION":
                return handleSunion(args);
                
            // 有序集合命令
            case "ZADD":
                return handleZadd(args);
            case "ZREM":
                return handleZrem(args);
            case "ZRANGE":
                return handleZrange(args);
            case "ZREVRANK":
                return handleZrevrank(args);
            case "ZINCRBY":
                return handleZincrby(args);
                
            // 哈希命令
            case "HSET":
                return handleHset(args);
            case "HGET":
                return handleHget(args);
            case "HMGET":
                return handleHmget(args);
            case "HINCRBY":
                return handleHincrby(args);
            case "HKEYS":
                return handleHkeys(args);
                
            // 事务命令
            case "MULTI":
                return handleMulti(args);
            case "EXEC":
                return handleExec(args);
            case "DISCARD":
                return handleDiscard(args);
            case "WATCH":
                return handleWatch(args);
                
            // 发布订阅命令
            case "PUBLISH":
                return handlePublish(args);
            case "SUBSCRIBE":
                return handleSubscribe(args);
            case "PSUBSCRIBE":
                return handlePsubscribe(args);
            case "UNSUBSCRIBE":
                return handleUnsubscribe(args);
            case "PUNSUBSCRIBE":
                return handlePunsubscribe(args);
                
            // 持久化命令
            case "SAVE":
                return handleSave(args);
            case "BGSAVE":
                return handleSave(args);
                
            // 服务器命令
            case "PING":
                return "PONG";
            case "ECHO":
                return args.length > 0 ? args[0] : "";
            case "INFO":
                return "# Server\\nredis_version:nano-redis-1.0\\nkeys:" + core.keys().size();
                
            default:
                return "-ERR unknown command '" + command + "'";
        }
    }

    /**
     * 解析Redis命令行
     */
    private String[] parseCommand(String commandLine) {
        List<String> parts = new ArrayList<>();
        StringBuilder current = new StringBuilder();
        boolean inQuotes = false;

        for (char c : commandLine.trim().toCharArray()) {
            if (c == '"') {
                inQuotes = !inQuotes;
            } else if (c == ' ' && !inQuotes) {
                if (current.length() > 0) {
                    parts.add(current.toString());
                    current.setLength(0);
                }
            } else {
                current.append(c);
            }
        }

        if (current.length() > 0) {
            parts.add(current.toString());
        }

        return parts.toArray(new String[0]);
    }

    // 键操作命令处理方法
    private Object handleSet(String[] args) {
        if (args.length < 2) {
            return "-ERR wrong number of arguments for 'set' command";
        }
        
        String key = args[0];
        String value = args[1];
        
        // 处理SET命令的选项（NX, PX等）
        if (args.length > 2) {
            String[] options = Arrays.copyOfRange(args, 2, args.length);
            String result = stringRedis.set(key, value, options);
            return result != null ? "+OK" : "$-1";
        } else {
            String result = stringRedis.set(key, value);
            return "+" + result;
        }
    }

    private Object handleGet(String[] args) {
        if (args.length != 1) {
            return "-ERR wrong number of arguments for 'get' command";
        }
        String value = stringRedis.get(args[0]);
        return value != null ? "$" + value.length() + "\\r\\n" + value : "$-1";
    }

    private Object handleDel(String[] args) {
        if (args.length < 1) {
            return "-ERR wrong number of arguments for 'del' command";
        }
        long count = 0;
        for (String key : args) {
            if (core.exists(key)) {
                core.remove(key);
                count++;
            }
        }
        return ":" + count;
    }

    private Object handleExpire(String[] args) {
        if (args.length != 2) {
            return "-ERR wrong number of arguments for 'expire' command";
        }
        try {
            long seconds = Long.parseLong(args[1]);
            if (!core.exists(args[0])) {
                return ":0";
            }
            core.expire(args[0], seconds);
            return ":1";
        } catch (NumberFormatException e) {
            return "-ERR value is not an integer or out of range";
        }
    }

    private Object handleTtl(String[] args) {
        if (args.length != 1) {
            return "-ERR wrong number of arguments for 'ttl' command";
        }
        return ":" + core.ttl(args[0]);
    }

    private Object handleExists(String[] args) {
        if (args.length < 1) {
            return "-ERR wrong number of arguments for 'exists' command";
        }
        long count = 0;
        for (String key : args) {
            if (core.exists(key)) {
                count++;
            }
        }
        return ":" + count;
    }

    // 字符串命令处理方法
    private Object handleIncr(String[] args) {
        if (args.length != 1) {
            return "-ERR wrong number of arguments for 'incr' command";
        }
        Long result = stringRedis.incr(args[0]);
        return result != null ? ":" + result : "-ERR value is not an integer or out of range";
    }

    private Object handleDecr(String[] args) {
        if (args.length != 1) {
            return "-ERR wrong number of arguments for 'decr' command";
        }
        Long result = stringRedis.decr(args[0]);
        return result != null ? ":" + result : "-ERR value is not an integer or out of range";
    }

    private Object handleMset(String[] args) {
        if (args.length < 2 || args.length % 2 != 0) {
            return "-ERR wrong number of arguments for 'mset' command";
        }
        String result = stringRedis.mset(args);
        return result != null ? "+OK" : "-ERR";
    }

    private Object handleMget(String[] args) {
        if (args.length < 1) {
            return "-ERR wrong number of arguments for 'mget' command";
        }
        String[] values = stringRedis.mget(args);
        StringBuilder response = new StringBuilder("*" + values.length + "\\r\\n");
        for (String value : values) {
            if (value != null) {
                response.append("$").append(value.length()).append("\\r\\n").append(value).append("\\r\\n");
            } else {
                response.append("$-1\\r\\n");
            }
        }
        return response.toString();
    }

    // 列表命令处理方法
    private Object handleLpush(String[] args) {
        if (args.length < 2) {
            return "-ERR wrong number of arguments for 'lpush' command";
        }
        String key = args[0];
        String[] values = Arrays.copyOfRange(args, 1, args.length);
        Long result = listRedis.lpush(key, values);
        return ":" + result;
    }

    private Object handleRpush(String[] args) {
        if (args.length < 2) {
            return "-ERR wrong number of arguments for 'rpush' command";
        }
        String key = args[0];
        String[] values = Arrays.copyOfRange(args, 1, args.length);
        Long result = listRedis.rpush(key, values);
        return ":" + result;
    }

    private Object handleLpop(String[] args) {
        if (args.length != 1) {
            return "-ERR wrong number of arguments for 'lpop' command";
        }
        String result = listRedis.lpop(args[0]);
        return result != null ? "$" + result.length() + "\\r\\n" + result : "$-1";
    }

    private Object handleRpop(String[] args) {
        if (args.length != 1) {
            return "-ERR wrong number of arguments for 'rpop' command";
        }
        String result = listRedis.rpop(args[0]);
        return result != null ? "$" + result.length() + "\\r\\n" + result : "$-1";
    }

    private Object handleLrange(String[] args) {
        if (args.length != 3) {
            return "-ERR wrong number of arguments for 'lrange' command";
        }
        try {
            String key = args[0];
            long start = Long.parseLong(args[1]);
            long end = Long.parseLong(args[2]);
            List<String> result = listRedis.lrange(key, start, end);
            StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
            for (String value : result) {
                response.append("$").append(value.length()).append("\\r\\n").append(value).append("\\r\\n");
            }
            return response.toString();
        } catch (NumberFormatException e) {
            return "-ERR value is not an integer or out of range";
        }
    }

    private Object handleBlpop(String[] args) {
        if (args.length < 2) {
            return "-ERR wrong number of arguments for 'blpop' command";
        }
        try {
            String key = args[0];
            long timeout = Long.parseLong(args[args.length - 1]);
            String result = listRedis.blpop(key, timeout);
            if (result != null) {
                return "*2\\r\\n$" + key.length() + "\\r\\n" + key + "\\r\\n$" + result.length() + "\\r\\n" + result;
            } else {
                return "$-1";
            }
        } catch (NumberFormatException e) {
            return "-ERR value is not an integer or out of range";
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return "-ERR interrupted";
        }
    }

    // 其他命令处理方法的简化实现
    private Object handleSadd(String[] args) {
        if (args.length < 2) return "-ERR wrong number of arguments for 'sadd' command";
        String key = args[0];
        String[] members = Arrays.copyOfRange(args, 1, args.length);
        Long result = setRedis.sadd(key, members);
        return ":" + result;
    }

    private Object handleSrem(String[] args) {
        if (args.length < 2) return "-ERR wrong number of arguments for 'srem' command";
        String key = args[0];
        String[] members = Arrays.copyOfRange(args, 1, args.length);
        Long result = setRedis.srem(key, members);
        return ":" + result;
    }

    private Object handleSmembers(String[] args) {
        if (args.length != 1) return "-ERR wrong number of arguments for 'smembers' command";
        Set<String> result = setRedis.smembers(args[0]);
        StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
        for (String member : result) {
            response.append("$").append(member.length()).append("\\r\\n").append(member).append("\\r\\n");
        }
        return response.toString();
    }

    private Object handleSinter(String[] args) {
        if (args.length < 1) return "-ERR wrong number of arguments for 'sinter' command";
        Set<String> result = setRedis.sinter(args);
        StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
        for (String member : result) {
            response.append("$").append(member.length()).append("\\r\\n").append(member).append("\\r\\n");
        }
        return response.toString();
    }

    private Object handleSunion(String[] args) {
        if (args.length < 1) return "-ERR wrong number of arguments for 'sunion' command";
        Set<String> result = setRedis.sunion(args);
        StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
        for (String member : result) {
            response.append("$").append(member.length()).append("\\r\\n").append(member).append("\\r\\n");
        }
        return response.toString();
    }

    // 有序集合命令（简化实现）
    private Object handleZadd(String[] args) {
        if (args.length < 3 || args.length % 2 == 0) return "-ERR wrong number of arguments for 'zadd' command";
        try {
            String key = args[0];
            long added = 0;
            for (int i = 1; i < args.length; i += 2) {
                double score = Double.parseDouble(args[i]);
                String member = args[i + 1];
                added += sortedSetRedis.zadd(key, score, member);
            }
            return ":" + added;
        } catch (NumberFormatException e) {
            return "-ERR value is not a valid float";
        }
    }

    private Object handleZrem(String[] args) {
        if (args.length < 2) return "-ERR wrong number of arguments for 'zrem' command";
        String key = args[0];
        String[] members = Arrays.copyOfRange(args, 1, args.length);
        Long result = sortedSetRedis.zrem(key, members);
        return ":" + result;
    }

    private Object handleZrange(String[] args) {
        if (args.length != 3) return "-ERR wrong number of arguments for 'zrange' command";
        try {
            String key = args[0];
            long start = Long.parseLong(args[1]);
            long end = Long.parseLong(args[2]);
            List<String> result = sortedSetRedis.zrange(key, start, end);
            StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
            for (String member : result) {
                response.append("$").append(member.length()).append("\\r\\n").append(member).append("\\r\\n");
            }
            return response.toString();
        } catch (NumberFormatException e) {
            return "-ERR value is not an integer or out of range";
        }
    }

    private Object handleZrevrank(String[] args) {
        if (args.length != 2) return "-ERR wrong number of arguments for 'zrevrank' command";
        Long result = sortedSetRedis.zrevrank(args[0], args[1]);
        return result != null ? ":" + result : "$-1";
    }

    private Object handleZincrby(String[] args) {
        if (args.length != 3) return "-ERR wrong number of arguments for 'zincrby' command";
        try {
            String key = args[0];
            double increment = Double.parseDouble(args[1]);
            String member = args[2];
            Double result = sortedSetRedis.zincrby(key, increment, member);
            return "$" + String.valueOf(result).length() + "\\r\\n" + result;
        } catch (NumberFormatException e) {
            return "-ERR value is not a valid float";
        }
    }

    // 哈希命令
    private Object handleHset(String[] args) {
        if (args.length != 3) return "-ERR wrong number of arguments for 'hset' command";
        Long result = hashRedis.hset(args[0], args[1], args[2]);
        return ":" + result;
    }

    private Object handleHget(String[] args) {
        if (args.length != 2) return "-ERR wrong number of arguments for 'hget' command";
        String result = hashRedis.hget(args[0], args[1]);
        return result != null ? "$" + result.length() + "\\r\\n" + result : "$-1";
    }

    private Object handleHmget(String[] args) {
        if (args.length < 2) return "-ERR wrong number of arguments for 'hmget' command";
        String key = args[0];
        String[] fields = Arrays.copyOfRange(args, 1, args.length);
        List<String> result = hashRedis.hmget(key, fields);
        StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
        for (String value : result) {
            if (value != null) {
                response.append("$").append(value.length()).append("\\r\\n").append(value).append("\\r\\n");
            } else {
                response.append("$-1\\r\\n");
            }
        }
        return response.toString();
    }

    private Object handleHincrby(String[] args) {
        if (args.length != 3) return "-ERR wrong number of arguments for 'hincrby' command";
        try {
            String key = args[0];
            String field = args[1];
            long increment = Long.parseLong(args[2]);
            Long result = hashRedis.hincrby(key, field, increment);
            return result != null ? ":" + result : "-ERR hash value is not an integer";
        } catch (NumberFormatException e) {
            return "-ERR value is not an integer or out of range";
        }
    }

    private Object handleHkeys(String[] args) {
        if (args.length != 1) return "-ERR wrong number of arguments for 'hkeys' command";
        Set<String> result = hashRedis.hkeys(args[0]);
        StringBuilder response = new StringBuilder("*" + result.size() + "\\r\\n");
        for (String key : result) {
            response.append("$").append(key.length()).append("\\r\\n").append(key).append("\\r\\n");
        }
        return response.toString();
    }

    // 事务命令处理方法
    private Object handleMulti(String[] args) {
        if (args.length != 0) return "-ERR wrong number of arguments for 'multi' command";
        return "+" + transactionRedis.multi("default");
    }

    private Object handleExec(String[] args) {
        if (args.length != 0) return "-ERR wrong number of arguments for 'exec' command";
        List<Object> results = transactionRedis.exec("default");
        if (results == null) {
            return "$-1";
        }
        StringBuilder response = new StringBuilder("*" + results.size() + "\\r\\n");
        for (Object result : results) {
            response.append("+").append(result).append("\\r\\n");
        }
        return response.toString();
    }

    private Object handleDiscard(String[] args) {
        if (args.length != 0) return "-ERR wrong number of arguments for 'discard' command";
        return "+" + transactionRedis.discard("default");
    }

    private Object handleWatch(String[] args) {
        if (args.length < 1) return "-ERR wrong number of arguments for 'watch' command";
        return "+" + transactionRedis.watch("default", args);
    }

    // 发布订阅命令处理方法
    private Object handlePublish(String[] args) {
        if (args.length != 2) return "-ERR wrong number of arguments for 'publish' command";
        long count = pubSubRedis.publish(args[0], args[1]);
        return ":" + count;
    }

    private Object handleSubscribe(String[] args) {
        if (args.length < 1) return "-ERR wrong number of arguments for 'subscribe' command";
        ClientSubscriber subscriber = clientSubscribers.computeIfAbsent("default", 
            k -> new ClientSubscriber(k, this));
        long count = pubSubRedis.subscribe(subscriber, args);
        return ":" + count;
    }

    private Object handlePsubscribe(String[] args) {
        if (args.length < 1) return "-ERR wrong number of arguments for 'psubscribe' command";
        ClientSubscriber subscriber = clientSubscribers.computeIfAbsent("default", 
            k -> new ClientSubscriber(k, this));
        long count = pubSubRedis.psubscribe(subscriber, args);
        return ":" + count;
    }

    private Object handleUnsubscribe(String[] args) {
        ClientSubscriber subscriber = clientSubscribers.get("default");
        if (subscriber == null) return ":0";
        long count = pubSubRedis.unsubscribe(subscriber, args);
        return ":" + count;
    }

    private Object handlePunsubscribe(String[] args) {
        ClientSubscriber subscriber = clientSubscribers.get("default");
        if (subscriber == null) return ":0";
        long count = pubSubRedis.punsubscribe(subscriber, args);
        return ":" + count;
    }

    // 持久化命令
    private Object handleSave(String[] args) {
        persistenceManager.save();
        return "+OK";
    }

    /**
     * 客户端订阅者实现
     */
    public static class ClientSubscriber implements PubSubRedis.Subscriber {
        private final String clientId;
        private final CommandProcessor processor;
        
        public ClientSubscriber(String clientId, CommandProcessor processor) {
            this.clientId = clientId;
            this.processor = processor;
        }
        
        @Override
        public void onMessage(String channel, String message) {
            System.out.println("Message to client " + clientId + " on channel " + channel + ": " + message);
        }
        
        @Override
        public void onPatternMessage(String pattern, String channel, String message) {
            System.out.println("Pattern message to client " + clientId + " on pattern " + pattern + ", channel " + channel + ": " + message);
        }
        
        @Override
        public String getId() {
            return clientId;
        }
    }

    /**
     * 判断是否为写命令
     */
    private boolean isWriteCommand(String command) {
        // JDK8兼容的写法，不使用Set.of
        Set<String> writeCommands = new HashSet<>();
        writeCommands.add("SET");
        writeCommands.add("DEL");
        writeCommands.add("EXPIRE");
        writeCommands.add("INCR");
        writeCommands.add("DECR");
        writeCommands.add("MSET");
        writeCommands.add("LPUSH");
        writeCommands.add("RPUSH");
        writeCommands.add("LPOP");
        writeCommands.add("RPOP");
        writeCommands.add("SADD");
        writeCommands.add("SREM");
        writeCommands.add("ZADD");
        writeCommands.add("ZREM");
        writeCommands.add("ZINCRBY");
        writeCommands.add("HSET");
        writeCommands.add("HINCRBY");
        
        return writeCommands.contains(command.toUpperCase());
    }

    /**
     * 获取Redis核心实例（用于测试）
     */
    public RedisCore getCore() {
        return core;
    }
}